package jmine.tec.web.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jmine.tec.services.ServicesController;
import jmine.tec.services.api.ServiceExecutionException;
import jmine.tec.services.api.ServicesPage;
import jmine.tec.services.api.factory.ServiceCreationException;
import bancosys.tec.rtm.impl.RtmController;

/**
 * Servlet para executar servicos sobre HTTP
 * <p>
 * Os parametros do servico devem ser passados como parametros da url assim:
 * <p>
 * service0.action => tipo do servico
 * <p>
 * service0.name => nome do servico
 * <p>
 * service0.param.param0 => valor de parametros
 * <p>
 * service0.param.param1 => valor de parametros
 * <p>
 * ...
 * <p>
 * até 10 servicos podem ser executados em 1 soh request (0...9)
 * <p>
 * Alem disso, os parametros denotados por output sao renderizados como resposta. Ex: service0.output=saida0,saida1
 * <p>
 * E sao renderizados, a principio, em formato XML
 * 
 * @author takeshi
 */
public class ServiceExecutionServlet extends BeanFactoryServlet {

    public static final int ERROR_STATUS_CODE = 510;

    public static final String TAG_ERRO_INTERNA_FECH = "</jterror>";

    public static final String TAG_ERRO_INTERNA = "<jterror>";

    private ServiceRequestParser serviceRequestParser;

    private ServicesController servicesController;

    private RtmController rtmController;

    /**
     * Responsável por parsear as requisições e transformar em serviços, e colocar no response o resultado da execução dos mesmos.
     * 
     * @param request {@link HttpServletRequest}
     * @param response {@link HttpServletResponse}
     * @throws IOException Se ocorrer erro ao colocar no response o tratamento de erro.
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        this.setUpResponseHeader(response);

        try {
            ServicesPage servicesPage = this.parse(request);
            this.execute(servicesPage);
        } catch (Throwable e) {
            this.handleException(response, e);
        }
    }

    /**
     * Executa o parseamento dos parâmetros da request e transforma em um ServicesPage.
     * 
     * @param request {@link HttpServletRequest}
     * @return {@link ServicesPage}
     * @throws ServiceCreationException se ocorrer erro na criação dos serviços.
     */
    private ServicesPage parse(HttpServletRequest request) throws ServiceCreationException {
        return this.getServiceRequestParser().parse(request);
    }

    /**
     * Executa a página de serviços.
     * 
     * @param servicesPage {@link ServicesPage}
     * @throws ServiceExecutionException Se ocorrer erro na execução dos serviços.
     */
    private void execute(ServicesPage servicesPage) throws ServiceExecutionException {
        this.getServicesController().executeServicesPage(servicesPage);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }

    /**
     * Grava a mensagem da exceção no response e o marca com erro 510.
     * 
     * @param response response.
     * @param t exceção que causou a falha na execução do serviço.
     * @throws IOException caso ocorra erro ao gravar o response.
     */
    private void handleException(HttpServletResponse response, Throwable t) throws IOException {
        this.getRtmController().monitor(t);
        StringBuilder sb = new StringBuilder();
        sb.append(TAG_ERRO_INTERNA);
        if (t instanceof ServiceExecutionException) {
            for (Throwable tt : ((ServiceExecutionException) t).getCauses()) {
                sb.append(tt.getMessage());
            }
        } else {
            sb.append(t.getMessage());
        }
        sb.append(TAG_ERRO_INTERNA_FECH);
        response.sendError(ERROR_STATUS_CODE, sb.toString());
    }

    /**
     * Define os atributos do cabeçalho do response.
     * 
     * @param response response.
     */
    private void setUpResponseHeader(HttpServletResponse response) {
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Content-Type", "text/html; charset=UTF-8");
        response.setDateHeader("Expires", 0);
    }

    /**
     * @return Parseador de parametros para servicos.
     */
    public ServiceRequestParser getServiceRequestParser() {
        if (this.serviceRequestParser == null) {
            this.serviceRequestParser = this.getBean("serviceRequestParser", ServiceRequestParser.class);
        }
        return this.serviceRequestParser;
    }

    /**
     * @return the servicesController
     */
    public ServicesController getServicesController() {
        if (this.servicesController == null) {
            this.servicesController = this.getBean("servicesController", ServicesController.class);
        }
        return this.servicesController;
    }

    /**
     * @return the servicesController
     */
    public RtmController getRtmController() {
        if (this.rtmController == null) {
            this.rtmController = this.getBean("rtmController", RtmController.class);
        }
        return this.rtmController;
    }

    /**
     * @param serviceRequestParser the serviceRequestParser to set
     */
    public void setServiceRequestParser(ServiceRequestParser serviceRequestParser) {
        this.serviceRequestParser = serviceRequestParser;
    }

    /**
     * @param servicesController the servicesController to set
     */
    public void setServicesController(ServicesController servicesController) {
        this.servicesController = servicesController;
    }

    /**
     * @param rtmController the rtmController to set
     */
    public void setRtmController(RtmController rtmController) {
        this.rtmController = rtmController;
    }
}
